package com.yswy.common.utils.sms;

import cn.hutool.core.codec.Base64Encoder;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@Service
public class CjSmsUtil {
    @Value(value = "${SMS.CJ.spId}")
    private String sp_id ;
    @Value(value = "${SMS.CJ.password}")
    private String password ;
    @Value(value = "${SMS.CJ.url}")
    private String url ;
//    public static final String url = "http://120.79.113.147:9511/api/send-sms-single";
//    public static final String sp_id = "912823";
//    public static final String password = "35512be33eaf829d27eb7b5462eb9ce4";


    public static void main(String[] args) {
//        sendCodeMsg("18080455214" , "123456" , "惠省心");
//        sendCodeMsg("18080455214" , "123456" , "团宠卡");
//        sendMsg("18080455214" , "您已支付成功，下载app查收话费券包，如需下载及售后点击： https://s.r.sn.cn/gY972M " , "惠省心");
    }

    public  void sendCodeMsg(String phone,  String  code  , String title){
        try {
            MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
            paramMap.add("sp_id", sp_id);
            paramMap.add("mobile", phone);
            paramMap.add("content", "【"+title+"】您的验证码为："+code+"，该验证码5分钟内有效，请勿泄漏他人。");
//        String signature = signature(paramMap, "340419fd");
//        paramMap.add("signature", signature);
            // MD5 32位小写
            paramMap.add("password", password);

            RestTemplate restTemplate = new RestTemplate();
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
            String result = restTemplate.postForObject(url, httpEntity, String.class);
            System.out.printf("\n%s\n", result);

        }
        catch (Exception  e){
            e.printStackTrace();
        }
    }

    public  void sendMsg(String phone,  String  msg, String title){
        try {
            MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
            paramMap.add("sp_id", sp_id);
            paramMap.add("mobile", phone);
            paramMap.add("content", "【"+title+"】"+msg);
//        String signature = signature(paramMap, "340419fd");
//        paramMap.add("signature", signature);
            // MD5 32位小写
            paramMap.add("password", password);

            RestTemplate restTemplate = new RestTemplate();
            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
            String result = restTemplate.postForObject(url, httpEntity, String.class);
            System.out.printf("\n%s\n", result);

        }
        catch (Exception  e){
            e.printStackTrace();
        }
    }



    private static String signature(MultiValueMap<String, Object> paramMap, String pwd) {
        /*
        一、准备QueryString
            将所有参数（除了signature）按照key排序（顺序）
            将排序好的参数key和值进行URLEncode，之后再增加三种字符替换：加号（+）替换成 %20、星号（*）替换成 %2A、%7E 替换回波浪号（~）
            将格式化后的key和值按照key + "=" + 值进行拼接成字符串QueryString，多个参数间用&连接，例：”a=%E5%93%88%E5%93%88&b=haha”
            在上一步得到的QueryString前拼接上请求方式，生成新的QueryString，HTTPMethod + "&" + URLEncode("/") + "&" + QueryString
        二、准备signature
            将上面得到的QueryString进行HmacSHA1算法进行编码，HMAC生成信息摘时需要用您的产品密码作为密钥。
            之后将上面加编码后的字符串进行base64编码，得到签名signature
         */
        String queryString = queryString(paramMap);
        return signature(queryString, pwd);
    }
    private static String queryString(MultiValueMap<String, Object> params) {

        // 根据参数Key排序（顺序）
        TreeMap<String, Object> sortParams = new TreeMap<>(params);
        // URLEncode
        String urlEncode = http_build_query(sortParams);
        // 字符替换
        String sortedQueryString = specialUrlEncode(urlEncode);
        // URLEncoder.encode("", "UTF-8")
        return String.format("POST&%s&%s", "%2F", sortedQueryString);
    }
    private static String signature(String queryString, String pwd) {
        // 签名采用HmacSHA1算法 + Base64。
        return getSignature(queryString, pwd);
    }
    private static String specialUrlEncode(String value) {
        return value.replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
    }
    private static String toUtf8(Object value) {
        try {
            return URLEncoder.encode(value.toString(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    private static String getSignature(String data, String key) {
        try {
            String s = "HmacSHA1";
            byte[] keyBytes = key.getBytes();
            SecretKeySpec signingKey = new SecretKeySpec(keyBytes, s);
            Mac mac = Mac.getInstance(s);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(data.getBytes());
            String hexBytes = byte2hex(rawHmac);
            return new Base64Encoder().encode(hexBytes.getBytes());
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return "";
    }
    private static String byte2hex(final byte[] b) {
        StringBuilder hs = new StringBuilder();
        AtomicReference<String> str = new AtomicReference<>();
        for (byte value : b) {
            str.set((Integer.toHexString(value & 0xFF)));
            hs.append(str.get().length() == 1 ? "0" : "").append(str.get());
        }
        return hs.toString();

    }
    private static String http_build_query(Map<String, Object> array) {
        StringBuilder sb = new StringBuilder();
        array.forEach((k, v) -> sb.append(k).append("=").append(toUtf8(v)).append("&"));
        sb.delete(sb.length() - 1, sb.length());
        return sb.toString();
    }

}
